using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityGameFramework.Runtime;

namespace LS.GameKit
{
    public class CommandReceiver : GameEventBehaviour
    {
        private Dictionary<string, List<System.Action<CommandType, object[]>>> m_EventModuleHandler = new Dictionary<string, List<System.Action<CommandType, object[]>>>();
        private List<System.Action<CommandType, object[]>> m_ReceiverObjectHandlers = new List<System.Action<CommandType, object[]>>();

        public Dictionary<string, System.Action<CommandType, object[]>[]> GetEventModules()
        {
            Dictionary<string, System.Action<CommandType, object[]>[]> d = new Dictionary<string, System.Action<CommandType, object[]>[]>();

            foreach (var item in m_EventModuleHandler)
            {
                d.Add(item.Key, item.Value.ToArray());
            }

            return d;
        }

        public System.Action<CommandType, object[]>[] GetReceiverObjectHandlers()
        {
            return m_ReceiverObjectHandlers.ToArray();
        }

        protected override void SubscribeAllEvents(EventComponent handler)
        {
            handler.Subscribe(GameBehaviourEventArgs.EventId, OnGameCommandEvent);
        }

        protected override void UnsubscribeAllEvents(EventComponent handler)
        {
            handler.Unsubscribe(GameBehaviourEventArgs.EventId, OnGameCommandEvent);
        }

        public void Receive(CommandType command, params object[] values)
        {
            Internal_Receive(CommandChannel.UnityEvent, null, command, values);
        }
        
        internal void ReceiveByObject(CommandType command, params object[] values)
        {
            Internal_Receive(CommandChannel.ReceiverObject, null, command, values);
        }

        private void Internal_Receive(CommandChannel channel, string key, CommandType command, params object[] values)
        {
            if (channel == CommandChannel.All || channel == CommandChannel.EventModule)
            {
                if (!string.IsNullOrEmpty(key) && m_EventModuleHandler.TryGetValue(key, out var list))
                {
                    foreach (var item in list)
                        item?.Invoke(command,  values);
                }
            }

            if (channel == CommandChannel.All || channel == CommandChannel.ReceiverObject)
            {
                foreach (var item in m_ReceiverObjectHandlers)
                    item?.Invoke(command, values);
            }
        }

        private void OnGameCommandEvent(object sender, GameFramework.Event.GameEventArgs args)
        {
            GameBehaviourEventArgs gameBehaviourEventArgs = args as GameBehaviourEventArgs;
            if (gameBehaviourEventArgs == null)
                return;
            CommandType gameCommandArgs = gameBehaviourEventArgs.CommandType.GetValueOrDefault(CommandType.None);
            object[] values = gameBehaviourEventArgs.Values.ToArray();
            Internal_Receive(CommandChannel.EventModule, gameBehaviourEventArgs.Key, gameCommandArgs, values);
        }

        public void Register(CommandHandler handler)
        {
            var channel = handler.Channel;
            if (channel == CommandChannel.All || channel == CommandChannel.EventModule)
            {
                if (string.IsNullOrEmpty(handler.Key))
                {
                    Debug.LogError($"CommandHandler[{handler.name}.key] is Enpty!");
                }
                else
                {
                    if (!m_EventModuleHandler.TryGetValue(handler.Key, out var list))
                    {
                        list = new List<System.Action<CommandType, object[]>>();
                        m_EventModuleHandler.Add(handler.Key, list);
                    }
                    list.Add(handler.OnCommand);
                }
            }
            if (channel == CommandChannel.All || channel == CommandChannel.ReceiverObject)
            {
                m_ReceiverObjectHandlers.Add(handler.OnCommand);
            }
        }

        public void Remove(CommandHandler handler)
        {
            var channel = handler.Channel;
            if (channel == CommandChannel.All || channel == CommandChannel.EventModule)
            {
                if (m_EventModuleHandler.TryGetValue(handler.Key, out var list))
                {
                    list = new List<System.Action<CommandType, object[]>>();
                    list.Remove(handler.OnCommand);
                    if (list.Count == 0)
                        m_EventModuleHandler.Remove(handler.Key);
                }
            }

            if (channel == CommandChannel.All || channel == CommandChannel.ReceiverObject)
            {
                m_ReceiverObjectHandlers.Remove(handler.OnCommand);
            }
        }
    }
}
